home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / clang / ebksrc.zip / EB2.CPP < prev    next >
C/C++ Source or Header  |  1991-08-10  |  13KB  |  556 lines

  1. /*
  2.  
  3.     eb2.cpp
  4.     8-10-91
  5.     Electronic Book
  6.  
  7.  
  8.     Copyright 1991
  9.     John W. Small
  10.     All rights reserved
  11.  
  12.     Licensed users of FlexList may use and modify this
  13.     tool for use in their programs.
  14.  
  15.  
  16.     PSW / Power SoftWare
  17.     P.O. Box 10072
  18.     McLean, Virginia 22102 8072 USA
  19.  
  20.     Voice: (703) 759-3838
  21.     CIS: 73757,2233
  22.  
  23.  
  24.     Notes:  The Electronic Book was coded to demonstrate
  25.     the various uses of FlexList.
  26.  
  27.  
  28. */
  29.  
  30. #include <ctype.h>
  31. #include <dos.h>
  32.  
  33. #include <eb1.hpp>
  34. #include <eb2.hpp>
  35. #include <pckey.hpp>
  36. #include <pcput2.hpp>
  37. #include <pcframe.hpp>
  38.  
  39.  
  40.  
  41. HyperLaunch::HyperLaunch(int imageX, int imageY,
  42.     const char *launch)
  43. {
  44.     ix = imageX;
  45.     iy = imageY;
  46.     this->launch = launch;
  47.     ilen = 0;
  48.     if (!launch)
  49.         return;
  50.     for (/* no init */; ilen < MAX_HYPER_LINE &&
  51.         launch[ilen]; ilen++)
  52.         if (launch[ilen] == HYPER_LAUNCH_DELIMIT)
  53.             break;
  54. }
  55.  
  56. void HyperLaunch::hilite(int winleft, int wintop,
  57.     int winwidth, int winheight, int attr)
  58. {
  59.     int x, y, i, l;
  60.  
  61.     if (iy < wintop)
  62.         return;
  63.     if ((y = iy - wintop + 1) > winheight)
  64.         return;
  65.     if (ix < winleft)
  66.         if (ix + ilen <= winleft)
  67.             return;  // launch left of window
  68.         else  {
  69.             x = 1;
  70.             i = winleft - ix;
  71.             if ((l = ilen - i) > winwidth)
  72.                 l = winwidth;
  73.         }
  74.     else if ((x = ix - winleft + 1) > winwidth)
  75.         return;  // launch right of window
  76.     else  {
  77.         i = 0;
  78.         if (x + ilen >= winwidth)
  79.             l = winwidth - x + 1;
  80.         else
  81.             l = ilen;
  82.     }
  83.     gotoxy(x,y);
  84.     textattr(attr);
  85.     cprintf("%.*s",l,&launch[i]);
  86. }
  87.  
  88. int HyperLaunch::match(const char *prefix, int pfLen)
  89. {
  90.     if (pfLen <= ilen)
  91.         if (!strncmpi(prefix,launch,pfLen))
  92.             return ix+pfLen-1;
  93.     return 0;
  94. }
  95.  
  96.  
  97. Palette HyperContext::defaultP =  {
  98.  
  99.     0,  /*  monochrome         or         color  */
  100.  
  101.     svideo(BLACK,LIGHTGRAY),    svideo(WHITE,BLUE),
  102.     svideo(DARKGRAY,LIGHTGRAY),    svideo(LIGHTRED,BLUE),
  103.     svideo(WHITE,BLACK),        svideo(BLUE,LIGHTGRAY)
  104. };
  105.  
  106. int HyperContext::defaultTabSpacing = 8;
  107.  
  108. void HyperContext::findLinesAndLaunches()
  109. {
  110.     int x, y, l;
  111.     unsigned inLaunch, i;
  112.     char *nline;
  113.     HyperLauncH HL;
  114.  
  115.     if ((nline = context) == (char *)0)
  116.         return;
  117.     for (x = y = 1, inLaunch = i = 0; i < clen; i++)  {
  118.         if (nline)  {
  119.             lines.insQD(&nline);
  120.             nline = (char *)0;
  121.         }
  122.         switch(context[i])  {
  123.         case HYPER_LAUNCH_DELIMIT:
  124.             if (context[i+1] ==
  125.                 HYPER_LAUNCH_DELIMIT)  {
  126.                 i++;
  127.                 x++;
  128.                 continue;
  129.             }
  130.             if (inLaunch)
  131.                 inLaunch = !inLaunch;
  132.             else if ((HL = new(launches.insQD())
  133.                 HyperLaunch(x,y,
  134.                 &context[++i]))
  135.                 != HyperLauncH0)  {
  136.                 l = HL->len();
  137.                 i += l;
  138.                 x += l;
  139.             }
  140.             else
  141.                 inLaunch  = !inLaunch;
  142.             break;
  143.         case '\r':
  144.             if (context[i+1] == '\n')
  145.                 i++;
  146.         case '\n':
  147.             x = 1;
  148.             y++;
  149.             nline = &context[i+1];
  150.             break;
  151.         case TAB:
  152.             while (x++ % tabSpacing)
  153.                 /* null stmt */;
  154.             break;
  155.         default:
  156.             x++;
  157.             break;
  158.         }
  159.     }
  160. }
  161.  
  162. HyperContext::HyperContext(char *context, unsigned clen,
  163.     const char *inlinks, const char *outlinks,
  164.     unsigned startRow, unsigned startColumn,
  165.     unsigned cursorRow, unsigned cursorColumn,
  166.     unsigned topicNum)
  167.     : lines(sizeof(char *)),
  168.     launches(sizeof(HyperLaunch))
  169. {
  170.     this ->context = context;
  171.     this->inlinks = strdup(inlinks);
  172.     this->outlinks = strdup(outlinks);
  173.     this->clen = clen;
  174.     choice = 0;
  175.     setPalette();
  176.     this->startRow = startRow;
  177.     this->startColumn = startColumn;
  178.     this->cursorRow = cursorRow;
  179.     this->cursorColumn = cursorColumn;
  180.     this->topicNum = topicNum;
  181.     tabSpacing = defaultTabSpacing;
  182.     prefix[pfLen=0] = '\0';
  183.     lines.setMaxNodes(MAX_HYPER_TOPIC_LINES);
  184.     launches.setMaxNodes(MAX_HYPER_TOPIC_LAUNCHES);
  185.     findLinesAndLaunches();
  186. }
  187.  
  188. HC_ACTIONS HyperContext::view()
  189. {
  190.     struct text_info ti;
  191.     ScrLnBuf scrbuf;
  192.     char *nline;
  193.     int x, y, i;
  194.     unsigned pgHeight, winHeight;
  195.     unsigned oldStartColumn, oldStartRow;
  196.     unsigned char scrollAttr;
  197.     unsigned scrollTopLeft, scrollBottomRight;
  198.     unsigned oldChoice;
  199.     HyperLauncH HL;
  200.  
  201.     PCF.reset();
  202.     gettextinfo(&ti);
  203.     mappalette(P);
  204.     mapvideo(NORMAL,P);
  205.     winHeight = ti.winbottom - ti.wintop + 1;
  206.     pgHeight = winHeight - 1;
  207.     scrbuf.set(mapattr(NORMAL,P),mapattr(HILITE,P),
  208.         ti.winright-ti.winleft+1,startColumn,1,'\r',
  209.         HYPER_LAUNCH_DELIMIT,tabSpacing);
  210.     if (cursorRow >= startRow + winHeight)
  211.         startRow = cursorRow - winHeight + 1;
  212.     else if (cursorRow < startRow)
  213.         startRow = cursorRow;
  214.     oldStartColumn = oldStartRow = 0;
  215.     scrollAttr = mapattr(NORMAL,P);
  216.     scrollBottomRight = ((ti.winbottom-1) << 8)
  217.         | (ti.winright-1);
  218.     scrollTopLeft = ((ti.wintop-1) << 8)
  219.         | (ti.winleft-1);
  220.  
  221.     prefix[pfLen = 0] = '\0';
  222.     oldChoice = choice = 0;
  223.  
  224.  
  225. while (1)  {
  226.     if (pfLen)  {  // find typed in hyper link
  227.         choice = 0;
  228.         for (launches.mkcur(); (HL = (HyperLauncH)
  229.             launches.nextD()) != HyperLauncH0;
  230.             /* no reinit */)  {
  231.             if ((x = HL->match(prefix,pfLen)) != 0)  {
  232.                 cursorColumn = x + 1;
  233.                 choice = launches.CurNum();
  234.                 cursorRow = HL->IY();
  235.                 break;
  236.             }
  237.         }
  238.         if (!choice)
  239.             prefix[pfLen = 0] = '\0';
  240.     }
  241.     else if (oldChoice != choice)  // find tabbed to hyper link
  242.         if ((HL = (HyperLauncH) launches.mkcur(choice))
  243.             != HyperLauncH0)  {
  244.             cursorRow = HL->IY();
  245.             cursorColumn = HL->IX();
  246.         }
  247.     if (cursorRow < startRow)
  248.         startRow = cursorRow;
  249.     else if (cursorRow >= startRow + winHeight)
  250.         startRow = cursorRow - winHeight + 1;
  251.     if (cursorColumn < scrbuf.startColumn)
  252.         scrbuf.startColumn = cursorColumn;
  253.     else if (cursorColumn >= scrbuf.startColumn
  254.         + scrbuf.pgWidth)
  255.         scrbuf.startColumn = cursorColumn
  256.             - scrbuf.pgWidth + 1;
  257.     if (oldStartColumn != scrbuf.startColumn ||
  258.         oldStartRow != startRow)  {
  259.         if (oldStartColumn == scrbuf.startColumn &&
  260.             oldStartRow &&
  261.             ((((y = oldStartRow-startRow) > 0)?
  262.             y : -y) <= 1))  {
  263.             // scroll up/down and insert line.
  264.             _DX = scrollBottomRight;
  265.             _CX = scrollTopLeft;
  266.             _BH = scrollAttr;
  267.             _AX = (y > 0)? 0x0701 : 0x0601;
  268.             geninterrupt(0x10);
  269.             y = (( y > 0)? startRow : startRow
  270.                 + winHeight - 1);
  271.             if (lines.recallD(&nline,y))
  272.                 scrbuf.put(nline,ti.winleft,
  273.                 ti.wintop+y-startRow);
  274.         }
  275.         else  {
  276.             lines.mkcur(startRow-1);
  277.             for (y = 0; y < winHeight &&
  278.                 lines.nextD(&nline); y++)  {
  279.                 scrbuf.put(nline,
  280.                     ti.winleft,ti.wintop+y);
  281.             }
  282.             while (y < winHeight)
  283.                 scrbuf.put((char *)0,
  284.                     ti.winleft,ti.wintop+y++);
  285.         }
  286.         oldStartColumn = scrbuf.startColumn;
  287.         oldStartRow = startRow;
  288.     }
  289.     if (!pfLen)  {  // find cursor moved over hyper link
  290.         choice = 0;
  291.         for (launches.mkcur(); (HL = (HyperLauncH)
  292.             launches.nextD()) != HyperLauncH0;
  293.             /* no reinit */)
  294.             if (HL->onLaunchPad(cursorColumn,cursorRow))  {
  295.                 choice = launches.CurNum();
  296.                 break;
  297.             }
  298.     }
  299.     if (oldChoice != choice)  { // New hyper link to hilite
  300.         if ((HL = (HyperLauncH) launches.mkcur(oldChoice))
  301.             != HyperLauncH0)
  302.             HL->hilite(scrbuf.startColumn,startRow,
  303.                 scrbuf.pgWidth,winHeight,
  304.                 mapattr(HILITE,P));
  305.         if ((HL = (HyperLauncH) launches.mkcur(choice))
  306.             != HyperLauncH0)
  307.             HL->hilite(scrbuf.startColumn,startRow,
  308.                 scrbuf.pgWidth,winHeight,
  309.                     mapattr(SELECT,P));
  310.         oldChoice = choice;
  311.     }
  312.     startColumn = scrbuf.startColumn; // save for hyperstack
  313.     gotoxy(cursorColumn-startColumn+1,
  314.         cursorRow-startRow+1);
  315.     pfLen = 0;   // get ready to erase prefix if not added to
  316.     switch (PCK.getkey())  {
  317.     case -Home:
  318.         cursorColumn = scrbuf.startColumn = 1;
  319.         break;
  320.     case -EndKey:
  321.         // compute line length;
  322.         if (lines.recallD(&nline,cursorRow))  {
  323.             scrbuf.writebuf(nline);
  324.             cursorColumn = scrbuf.eolColumn;
  325.         }
  326.         else
  327.             cursorColumn = 1;
  328.         if (cursorColumn < scrbuf.startColumn)
  329.             scrbuf.startColumn = cursorColumn;
  330.         else if (cursorColumn >=
  331.             scrbuf.startColumn + scrbuf.pgWidth)
  332.             scrbuf.startColumn = cursorColumn
  333.                 - scrbuf.pgWidth + 1;
  334.         break;
  335.     case CtrlS:
  336.     case -LArr:
  337.         if (cursorColumn > 1)
  338.             if (--cursorColumn < scrbuf.startColumn)
  339.                 scrbuf.startColumn = cursorColumn;
  340.         break;
  341.     case CtrlD:
  342.     case -RArr:
  343.         if (cursorColumn < MAX_HYPER_LINE)
  344.             if (++cursorColumn >=
  345.                 scrbuf.startColumn + scrbuf.pgWidth)
  346.                 scrbuf.startColumn = cursorColumn
  347.                 - scrbuf.pgWidth + 1;
  348.         break;
  349.     case -UpArr:
  350.         if (cursorRow > 1)
  351.             if (--cursorRow < startRow)
  352.                 startRow = cursorRow;
  353.         break;
  354.     case -DnArr:
  355.         if (cursorRow < lines.Nodes())  {
  356.             if (++cursorRow >= startRow + winHeight)
  357.                 startRow = cursorRow - winHeight + 1;
  358.         }
  359.         else if (startRow < cursorRow)
  360.             startRow++;
  361.         break;
  362.     case CtrlA:
  363.     case -CtrlLArr:
  364.         if (lines.recallD(&nline,cursorRow))  {
  365.             scrbuf.writebuf(nline);
  366.             if (cursorColumn > scrbuf.eolColumn)
  367.                 i = scrbuf.eolColumn - 1;
  368.             else
  369.                 i = cursorColumn - 1;
  370.             while (i && !isalnum((char)scrbuf.buf[i-1]))
  371.                 i--;
  372.             if (!i)  {
  373.                 if (cursorRow == 1)
  374.                     break;
  375.                 if (lines.recallD(&nline,cursorRow-1)) {
  376.                     cursorRow--;
  377.                     scrbuf.writebuf(nline);
  378.                     cursorColumn = scrbuf.eolColumn;
  379.                 }
  380.                 break;
  381.             }
  382.             while (i && isalnum((char)scrbuf.buf[i-1]))
  383.                 i--;
  384.             cursorColumn = i + 1;
  385.         }
  386.         break;
  387.     case CtrlF:
  388.     case -CtrlRArr:
  389.         lines.mkcur(cursorRow-1);
  390.         for (i = cursorColumn - 1; lines.nextD(&nline);
  391.             i = 0)  {
  392.             scrbuf.writebuf(nline);
  393.             x = scrbuf.eolColumn - 1;
  394.             if (i >= x)
  395.                 continue;
  396.             while (i < x && isalnum((char)scrbuf.buf[i])) i++;
  397.             if (i >= x)
  398.                 break;
  399.             while (i < x && !isalnum((char)scrbuf.buf[i])) i++;
  400.             if (i < x)
  401.                 break;
  402.         }
  403.         if (lines.CurNum())  {
  404.             cursorRow = lines.CurNum();
  405.             cursorColumn = i + 1;
  406.         }
  407.         break;
  408.     case -CtrlHome:
  409.         cursorRow = startRow;
  410.         break;
  411.     case -CtrlEnd:
  412.         if (startRow + winHeight - 1 > lines.Nodes())
  413.             cursorRow = lines.Nodes();
  414.         else
  415.             cursorRow = startRow + winHeight - 1;
  416.         break;
  417.     case -PgDn:
  418.         cursorRow += pgHeight;
  419.         if (cursorRow >= lines.Nodes())  {
  420.             cursorRow = lines.Nodes();
  421.             if (startRow + pgHeight > cursorRow)
  422.                 break;
  423.         }
  424.         startRow += pgHeight;
  425.         if (startRow > cursorRow)
  426.             startRow = cursorRow;
  427.         break;
  428.     case -PgUp:
  429.         if (cursorRow > pgHeight)
  430.             cursorRow -= pgHeight;
  431.         else
  432.             cursorRow = 1;
  433.         if (startRow > pgHeight)
  434.             startRow -= pgHeight;
  435.         else
  436.             startRow = 1;
  437.         break;
  438.     case -CtrlPgUp:
  439.         startRow = cursorRow = 1;
  440.         break;
  441.     case -CtrlPgDn:
  442.         cursorRow = lines.Nodes();
  443.         if (cursorRow >= startRow + winHeight)
  444.                 if (cursorRow > winHeight/2)
  445.                     startRow = cursorRow
  446.                         - winHeight/2;
  447.                 else
  448.                     startRow = 1;
  449.         break;
  450.     case CtrlZ:  // pan down
  451.         if (startRow < lines.Nodes())
  452.             if (++startRow > cursorRow)
  453.                 cursorRow = startRow;
  454.         break;
  455.     case CtrlW:  // pan up
  456.         if (startRow > 1)
  457.             if (--startRow + winHeight <= cursorRow)
  458.                 cursorRow = startRow + winHeight - 1;
  459.         break;
  460.     case -F1:
  461.         return HELP;
  462.     case -F3:
  463.         return LOAD;
  464.     case -F10:
  465.     case -AltT:
  466.         return TABLE_OF_CONTENTS;
  467.     case -AltF10:
  468.     case -AltI:
  469.         return INDEX;
  470.     case CR:
  471.         choice = 0;
  472.         for (launches.mkcur(); (HL = (HyperLauncH)
  473.             launches.nextD()) != HyperLauncH0;
  474.             /* no reinit */)
  475.             if (HL->onLaunchPad(cursorColumn,cursorRow))  {
  476.                 choice = launches.CurNum();
  477.                 return LAUNCH;
  478.             }
  479.         break;
  480.     case -AltF1:
  481.     case BACKSP:
  482.         return BACKUP;
  483.     case -ShiftF6:
  484.         return ATTR_TOGGLE;
  485.     case -F6:
  486.         return RES_TOGGLE;
  487.     case -AltX:
  488.         return EXIT;
  489.     case TAB:
  490.         if (!choice)  {  // find closest launch to cursor
  491.             for (launches.mkcur(); (HL = (HyperLauncH)
  492.                 launches.nextD()) != HyperLauncH0;
  493.                 /* no reinit */)
  494.                 if ((HL->IY() > cursorRow) ||
  495.                     ((HL->IY() == cursorRow) &&
  496.                     ((HL->IX() + HL->len())
  497.                     > cursorColumn)))
  498.                     break;
  499.             if ((choice = launches.CurNum()) == 0)
  500.                 choice = 1;
  501.         }
  502.         else if (choice < launches.Nodes())
  503.             choice++;
  504.         else
  505.             choice = 1;
  506.         break;
  507.     case -ShiftTab:
  508.         if (!choice)  {  // find closest launch to cursor
  509.             for (launches.mkcur(); (HL = (HyperLauncH)
  510.                 launches.prevD()) != HyperLauncH0;
  511.                 /* no reinit */)
  512.                 if ((HL->IY() < cursorRow) ||
  513.                     ((HL->IY() == cursorRow) &&
  514.                     (HL->IX() < cursorColumn)))
  515.                     break;
  516.             if ((choice = launches.CurNum()) == 0)
  517.                 choice = launches.Nodes();
  518.         }
  519.         else if (choice > 1)
  520.             choice--;
  521.         else
  522.             choice = launches.Nodes();
  523.         break;
  524.     default:
  525.         if ((pfLen = strlen(prefix)) >= MAX_HC_PREFIX - 1)
  526.                 continue;
  527.         if (!isprint(PCK.ascii()))
  528.             continue;
  529.         prefix[pfLen++] = toupper(PCK.ascii());
  530.         break;
  531.     }
  532.     prefix[pfLen] = '\0';
  533. }
  534.     return EXIT;
  535. }
  536.  
  537. char * HyperContext::newTarget()
  538. {
  539.     char *t;
  540.  
  541.     if (!choice) return (char *)0;
  542.     t = parseLinks(outlinks);
  543.     for (unsigned i = 1; i < choice; i++)
  544.         t = parseLinks();
  545.     return t;
  546. }
  547.  
  548. HyperContext::~HyperContext()
  549. {
  550.     delete context;
  551.     lines.clear();
  552.     launches.clear();
  553.     delete inlinks;
  554.     delete outlinks;
  555. }
  556.